package net.gdface.utils;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.common.io.BaseEncoding;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;

public class ArraySupport {

	/**
	 * cast byte array to HEX string
	 * 
	 * @param input
	 * @return {@code null} if {@code input} is null
	 */
	public static final String toHex(byte[] input) {
	    if (null == input){
	        return null;
	    }
	    return BaseEncoding.base16().encode(input);
	}

	/**
	 * Returns a big-endian representation HEX string
	 * @param input
	 */
	public static final String toHex(short[] input) {
		if (null == input){
			return null;
		}
		byte[][] output = new byte[input.length][];
		for(int i = 0;i<input.length;++i){    		
			output[i] = Shorts.toByteArray(input[i]);
		}
		return toHex(Bytes.concat(output));
	}

	/**
	 * Returns a big-endian representation HEX string
	 * @param input
	 */
	public static final String toHex(int[] input) {
		if (null == input){
			return null;
		}
		byte[][] output = new byte[input.length][];
		for(int i = 0;i<input.length;++i){    		
			output[i] = Ints.toByteArray(input[i]);
		}
		return toHex(Bytes.concat(output));
	}
	/**
	 * Returns a big-endian representation HEX string
	 * @param input
	 */
	public static final String toHex(long[] input) {
		if (null == input){
			return null;
		}
		byte[][] output = new byte[input.length][];
		for(int i = 0;i<input.length;++i){    		
			output[i] = Longs.toByteArray(input[i]);
		}
		return toHex(Bytes.concat(output));
	}

	/**
	 * cast HEX string to byte array
	 * @param input
	 * @return {@code null} if {@code input} is null
	 */
	public static final byte[] fromHex(String input){
		if (null == input){
			return null;
		}
		return BaseEncoding.base16().decode(input);    	
	}
	/**
	 * cast HEX string to short array,
	 * Returns the short value whose byte representation is the given 2 bytes, in big-endian order
	 * @param input
	 * @return {@code null} if {@code input} is null
	 */
	public static final  short[] fromHex(String input,short value){
		if (null == input){
			return null;
		}
		byte[] bytes = fromHex(input);
		int step = Short.SIZE/Byte.SIZE;
		checkArgument(0 == bytes.length%step,
				"INVALID input length %s,%s times required",input.length(),step);
		short[] output = new short[bytes.length%step];
		for(int i=0,j=0;i<output.length;++i,j+=step){
			output[i] = Shorts.fromBytes(bytes[j], bytes[j+1]); 
		}
		return output;
	}
	/**
	 * cast HEX string to int array,
	 * Returns the int value whose byte representation is the given 4 bytes, in big-endian order
	 * @param input
	 * @return {@code null} if {@code input} is null
	 */
	public static final int[] fromHex(String input,int value){
		if (null == input){
			return null;
		}
		byte[] bytes = fromHex(input);
		int step = Integer.SIZE/Byte.SIZE;
		checkArgument(0 == bytes.length%step,
				"INVALID input length %s,%s times required",input.length(),step);
		int[] output = new int[bytes.length%step];
		for(int i=0,j=0;i<output.length;++i,j+=step){
			output[i] = Ints.fromBytes(bytes[j], bytes[j+1], bytes[j+2], bytes[j+3]); 
		}
		return output;
	}
	/**
	 * cast HEX string to long array,
	 * Returns the long value whose byte representation is the given 8 bytes, in big-endian order
	 * @param input
	 * @return {@code null} if {@code input} is null
	 */
	public static final long[] fromHex(String input,long value){
		if (null == input){
			return null;
		}
		byte[] bytes = fromHex(input);
		int step = Long.SIZE/Byte.SIZE;
		checkArgument(0 == bytes.length%step,
				"INVALID input length %s,%s times required",input.length(),step);
		long[] output = new long[bytes.length%step];
		for(int i=0,j=0;i<output.length;++i,j+=step){
			output[i] = Longs.fromBytes(
					bytes[j], bytes[j+1], bytes[j+2], bytes[j+3],bytes[j+4], bytes[j+5], bytes[j+6], bytes[j+7]); 
		}
		return output;
	}
    /**
     * cast HEX string to byte array,copy to this destination,same length required with {@code dest}
     * @param hex
     * @param dest
     */
    public static void copyToByteArray(String hex, byte[] dest){
    	checkArgument(null != hex && null != dest,"hex or dest is null");
    	byte[] src = ArraySupport.fromHex(hex);
    	checkArgument(src.length == dest.length,"INVALID HEX String length, %s required",dest.length);
        System.arraycopy(src, 0, dest, 0, src.length);
    }
}
